package cn.lili.modules.member.serviceimpl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.SceneEnums;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.PageVO;
import cn.lili.exchange.AmqpExchangeProperties;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.member.entity.dto.*;
import cn.lili.modules.member.entity.vo.UserVO;
import cn.lili.modules.member.mapper.UserMapper;
import cn.lili.modules.member.service.ManagerUserService;
import cn.lili.modules.member.service.UserService;
import cn.lili.modules.permission.entity.dto.UserAdminDTO;
import cn.lili.modules.permission.entity.vo.AdminUserVO;
import cn.lili.modules.sensitive.SensitiveWordsFilter;
import cn.lili.mybatis.util.PageUtil;
import cn.lili.mybatis.util.SceneHelp;
import cn.lili.routing.UserRoutingKey;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 用户接口业务层实现
 *
 * @author Chopper
 * @since 2021-03-29 14:10:16
 */
@Service
@AllArgsConstructor
public class ManagerUserServiceImpl extends ServiceImpl<UserMapper, User> implements ManagerUserService {


    private final ApplicationEventPublisher applicationEventPublisher;

    private final AmqpExchangeProperties amqpExchangeProperties;

    private final Cache cache;

    @Override
    public User findByUsername(String userName, SceneEnums scene) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userName);
        queryWrapper.eq(User::getScene, scene.value());
        return this.getOne(queryWrapper, false);
    }


    @Override
    public UserVO userInfo() {
        AuthUser authUser = UserContext.getCurrentUser();
        assert authUser != null;
        User user = this.findByUsername(authUser.getUsername(), authUser.getScene());

        return new UserVO(user);
    }


    @Override
    public User userLoginQuery(UserLoginDTO userLoginDTO) {
        User user = this.findByUsername(userLoginDTO.getUsername(), userLoginDTO.getScene());
        //判断用户是否存在
        if (user == null || !user.getEnable()) {
            throw new ServiceException(ResultCode.USER_NOT_EXIST);
        }
        //判断密码是否输入正确
        if (!new BCryptPasswordEncoder().matches(userLoginDTO.getPassword(), user.getPassword())) {
            throw new ServiceException(ResultCode.USER_PASSWORD_ERROR);
        }
        return user;
    }


    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public User mobilePhoneLogin(String mobilePhone, SceneEnums scene) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobilePhone);
        queryWrapper.eq("scene", scene.value());
        User user = this.baseMapper.selectOne(queryWrapper);
        //如果手机号不存在则自动注册用户
        if (user == null) {
            UserInfoDTO userInfoDTO =
                    UserInfoDTO.builder().username(mobilePhone).mobile(mobilePhone).scene(scene).password(UserService.DEFAULT_PASSWORD).build();

            user = registerHandler(userInfoDTO);
        }
        return user;
    }


    @Override
    public User editOwn(UserInfoDTO userInfoDTO) {
        //查询用户信息
        User user = this.findByUsername(UserContext.getCurrentUser().getUsername(), UserContext.getCurrentUser().getScene());
        //传递修改用户信息
        BeanUtil.copyProperties(userInfoDTO, user);
        user.setId(UserContext.getCurrentId());
        //修改用户
        this.updateById(user);
        return user;
    }


    @Override
    @Transactional
    public User addUser(UserInfoDTO userInfoDTO) {
        //检测用户信息
        checkMember(userInfoDTO.getUsername(), userInfoDTO.getMobile(), userInfoDTO.getScene().value());
        //添加用户
        userInfoDTO.setPassword(new BCryptPasswordEncoder().encode(StringUtils.md5(userInfoDTO.getPassword())));
        return registerHandler(userInfoDTO);
    }

    @Override
    public AdminUserVO updateUser(UserEditDTO userEditDTO) {
        //过滤用户昵称敏感词
        if (CharSequenceUtil.isNotBlank(userEditDTO.getNickName())) {
            userEditDTO.setNickName(SensitiveWordsFilter.filter(userEditDTO.getNickName()));
        }
        //如果密码不为空则加密密码
        if (CharSequenceUtil.isNotBlank(userEditDTO.getPassword())) {
            userEditDTO.setPassword(new BCryptPasswordEncoder().encode(userEditDTO.getPassword()));
        }
        //查询用户信息
        User user = this.getById(userEditDTO.getId());

        //编辑用户时需要先判定用户信息是否可以编辑，判定依据为：修改用户的逻辑场景是否与数据库中一致，避免跨业务修改
        if (user == null || !SceneEnums.getScene(user.getScene()).equals(userEditDTO.getScene())) {
            throw new ServiceException(ResultCode.USER_NOT_EXIST);
        }

        user.setRoleIds(userEditDTO.getRoleIdsStr());
        //传递修改用户信息
        BeanUtil.copyProperties(userEditDTO, user);
        this.updateById(user);
        cache.vagueDel(CachePrefix.USER_MENU.getPrefix(SceneEnums.valueOf(user.getScene()), user.getId()));
        cache.vagueDel(CachePrefix.PERMISSION_LIST.getPrefix(SceneEnums.valueOf(user.getScene()), user.getId()));
        return new AdminUserVO(user);
    }

    @Override
    public Page<AdminUserVO> getUserPage(UserSearchParams userSearchParams, PageVO page) {

        QueryWrapper<AdminUserVO> queryWrapper = Wrappers.query();

        //用户名查询
        queryWrapper.like(CharSequenceUtil.isNotBlank(userSearchParams.getUsername()), "username", userSearchParams.getUsername());
        //用户名查询
        queryWrapper.like(CharSequenceUtil.isNotBlank(userSearchParams.getNickName()), "nick_name", userSearchParams.getNickName());
        //按照电话号码查询
        queryWrapper.like(CharSequenceUtil.isNotBlank(userSearchParams.getMobile()), "mobile", userSearchParams.getMobile());
        //按照用户状态查询
        queryWrapper.eq(userSearchParams.getEnable() != null, "enable", userSearchParams.getEnable()); //按照用户状态查询
        //必填场景参数
        queryWrapper.eq("u.scene", userSearchParams.getScene().name());
        //必填场景参数
        queryWrapper.eq(userSearchParams.getExtendId() != null, "u.extend_id", userSearchParams.getExtendId());

        //按照部门查询
        queryWrapper.eq(CharSequenceUtil.isNotEmpty(userSearchParams.getDepartmentId()), "department_id", userSearchParams.getDepartmentId());
        queryWrapper.eq("u.delete_flag", false);

        queryWrapper.orderByDesc("create_time");
        return this.baseMapper.userPage(PageUtil.initPage(page), queryWrapper);
    }

    /**
     * 获取用户列表
     *
     * @param searchParams 查询参数
     * @return 用户列表
     */
    @Override
    public List<User> list(UserSearchParams searchParams) {
        return this.list(searchParams.queryWrapper());
    }


    @Override
    public Boolean updateUserStatus(UserStatusChangeDTO userStatusChangeDTO) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getScene, userStatusChangeDTO.getScene().value());
        updateWrapper.eq(CharSequenceUtil.isNotEmpty(userStatusChangeDTO.getExtendId()), User::getExtendId, userStatusChangeDTO.getExtendId());
        // 限制修改admin用户
        updateWrapper.ne(User::getUsername, "admin");
        updateWrapper.set(User::getEnable, userStatusChangeDTO.getEnable());
        updateWrapper.in(User::getId, userStatusChangeDTO.getUserIds());
        return this.update(updateWrapper);
    }

    @Override
    public Boolean removeUser(UserStatusChangeDTO userStatusChangeDTO) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getScene, userStatusChangeDTO.getScene().value());
        //限制删除admin用户
        updateWrapper.ne(User::getUsername, "admin");
        updateWrapper.eq(CharSequenceUtil.isNotEmpty(userStatusChangeDTO.getExtendId()), User::getExtendId, userStatusChangeDTO.getExtendId());
        updateWrapper.in(User::getId, userStatusChangeDTO.getUserIds());
        return this.remove(updateWrapper);
    }

    @Override
    public long getMemberNum(UserSearchParams userSearchParams) {
        QueryWrapper<User> queryWrapper = Wrappers.query();
        //用户名查询
        queryWrapper.like(CharSequenceUtil.isNotBlank(userSearchParams.getUsername()), "username", userSearchParams.getUsername());
        //按照电话号码查询
        queryWrapper.like(CharSequenceUtil.isNotBlank(userSearchParams.getMobile()), "mobile", userSearchParams.getMobile());
        //按照状态查询
        queryWrapper.eq(userSearchParams.getEnable() != null, "enable", userSearchParams.getEnable());
        //场景筛选
        queryWrapper.eq("scene", userSearchParams.getScene().name());
        queryWrapper.orderByDesc("create_time");
        return this.count(queryWrapper);
    }

    /**
     * 获取指定用户数据
     *
     * @param columns 指定获取的列
     * @param userIds 用户ids
     * @return 指定用户数据
     */
    @Override
    public List<Map<String, Object>> listFieldsByMemberIds(String columns, List<String> userIds) {
        return this.listMaps(new QueryWrapper<User>().select(columns).in(userIds != null && !userIds.isEmpty(), "id", userIds));
    }

    /**
     * 获取所有用户的手机号
     *
     * @return 所有用户的手机号
     */
    @Override
    public List<String> getMemberMobile(PageVO pageVO) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getEnable, true);
        return this.baseMapper.getAllMemberMobile(PageUtil.initPage(pageVO), lambdaQueryWrapper);
    }

    /**
     * 更新用户登录时间为最新时间
     *
     * @param userId 用户id
     * @return 是否更新成功
     */
    @Override
    public Boolean updateUserLoginTime(String userId) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, userId);
        updateWrapper.set(User::getLastLoginDate, new Date());
        return this.update(updateWrapper);
    }


    /**
     * 注册方法抽象
     *
     * @param userInfoDTO 注册传输对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public User registerHandler(UserInfoDTO userInfoDTO) {
        User user = new User(userInfoDTO);
        user.setId(SnowFlake.getIdStr());
        //保存用户
        this.save(user);

        applicationEventPublisher.publishEvent(TransactionCommitSendMQEvent.builder().source("USER_REGISTER").exchange(amqpExchangeProperties.getUser()).routingKey(UserRoutingKey.USER_REGISTER).message(user).build());
        return user;
    }


    @Override
    public void saveUser(UserAdminDTO userAdminDTO) {
        this.save(new User(userAdminDTO));
    }

    @Override
    public User checkMobile(String mobile, SceneEnums sceneEnums) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getMobile, mobile);
        queryWrapper.eq(User::getScene, sceneEnums.value());
        return this.getOne(queryWrapper, false);
    }

    @Override
    public void resetPassword(List<String> ids) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("id", ids);
        updateWrapper.set("password", DEFAULT_PASSWORD);
        SceneHelp.queryHandler(updateWrapper, true);
        this.update(updateWrapper);
    }

    /**
     * 检测用户
     *
     * @param userName    用户名称
     * @param mobilePhone 手机号
     */
    private void checkMember(String userName, String mobilePhone, String scene) {
        //判断手机号是否存在
        if (findUser(mobilePhone, userName, scene) > 0) {
            throw new ServiceException(ResultCode.USER_EXIST);
        }
    }


    /**
     * 根据手机号获取用户
     *
     * @param mobilePhone 手机号
     * @param userName    用户名
     * @param scene       场景
     * @return 用户
     */
    private Long findUser(String mobilePhone, String userName, String scene) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getScene, scene).and(i -> i.eq(User::getMobile, mobilePhone).or().eq(User::getUsername, userName)).eq(User::getDeleteFlag, false);
        return this.baseMapper.selectCount(queryWrapper);
    }

}